/*
 * Copyright 2020-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package example.hello_security.config;

import example.hello_security.config.filter.JwtAuthenticationTokenFilter;
import example.hello_security.config.entrypoint.LoginUnAuthenticationEntryPoint;
import example.hello_security.config.handler.CustomAccessDenyHandler;
import example.hello_security.config.handler.CustomLogoutSuccessHandler;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * 这是一个jwt配置
 * 能够实现jwt的简单加密，jwt的算法是RSA
 * Security configuration for the main application.
 *
 * @author Josh Cummings
 */
@EnableWebSecurity()
@EnableMethodSecurity(securedEnabled = true, prePostEnabled = true) // 启动方法保护
@Configuration
public class WebSecurityConfig {
    // 自定义的未认证EntryPoint
    @Resource
    private LoginUnAuthenticationEntryPoint loginUnAuthenticationEntryPoint;
    @Resource
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Resource
    private CustomLogoutSuccessHandler customLogoutSuccessHandler;
    @Resource
    private CustomAccessDenyHandler customAccessDenyHandler;

    /**
     * description 定义filterChain
     * @author zken
     * CreateDate 2024/10/27 00:04:34
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/login").permitAll()
                        .anyRequest().authenticated()
                )
                .csrf((csrf) -> csrf.ignoringRequestMatchers("/login", "/logout")) // 忽略对login接口的CSRF
                .httpBasic(Customizer.withDefaults())
                .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));


        // 在UsernamePasswordAuthenticationFilter前进行添加一个filter
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        // 添加一个entryPoint已经弃用的写法
//        http.exceptionHandling().authenticationEntryPoint(loginUnAuthenticationEntryPoint);
        // entryPoint新版本的写法
        http.exceptionHandling(exceptionHandling -> {
            exceptionHandling.authenticationEntryPoint(loginUnAuthenticationEntryPoint);
            // 添加权限不足时刻拒绝处理器
            exceptionHandling.accessDeniedHandler(customAccessDenyHandler);
        });


        // 注册自定义logout处理器
        http.logout(logout -> logout.logoutSuccessHandler(customLogoutSuccessHandler));

        // @formatter:on
        return http.build();
    }


//    /**
//     * 测试用户注册到内存中，如果实现了接口service,可以不再使用InMemoryUserDetailsManager
//     * @author zken
//     * Date 2024/10/26 23:58:57
//     */
//    @Bean
//    UserDetailsService users() {
//        // @formatter:off
//		return new InMemoryUserDetailsManager(
//			User.withUsername("123")
//				.password("{noop}123")
//				.authorities("app")
//				.build()
//		);
//		// @formatter:on
//    }

    /**
     * description 自定义解码器
     * @author zken
     * CreateDate 2024/10/27 16:30:49
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    /**
     * description 配置认证管理器AuthenticationManager
     * @author zken
     * CreateDate 2024/10/27 16:30:07
     */
    @Bean
    AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) {
        try {
            return authenticationConfiguration.getAuthenticationManager();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


}
